(display "\n========================================\n")
;(display "square(21): ")
;(define (square x) (* x x))
;(display (square 21))
;(newline)
;
;(define (sum-of-squares x y)
;    (+ (square x) (square y)))
;
;(display "square sum(3 4): ")
;(display (sum-of-squares 3 4))
;(newline)
;
;(display "f(5): ")
;(define (f a)
;    (sum-of-squares (+ a 1) (* a 2)))
;(display (f 5))
;(newline)
;
;(display "abs(): ")
;(define (abs x)
;    (cond ((> x 0) x)
;          ((= x 0) 0)
;          ((< x 0) (- x))))
;(display (abs (- 5)))
;(newline)
;
;(display "abs1(): ")
;(define (abs1 x)
;    (cond ((< x 0) (- x))
;          (else x)))
;(display (abs1 (- 5)))
;(newline)
;
;(display "abs2(): ")
;(define (abs2 x)
;    (if (< x 0)
;        (- x)
;        x))
;(display (abs2 (- 1.5)))
;(newline)
;
;(display "not: ")
;(display (not (< 2 3)))
;(newline)
;
;(display ">=: ")
;(define (>= x y)
;    (or (> x y) (= x y)))
;(display (>= 3 3))
;(newline)
;
;(display "ex1.2: ")
;(display (/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5)))))
;            (* 3 (- 6 2) (- 2 7))))
;(newline)
;
;(display "ex1.3: ")
;(define (<= x y) (not (> x y)))
;(define (m-sum a b c)
;            (cond ((and (<= a b) (<= a c)) (+ b c))
;                  ((and (<= b a) (<= b c)) (+ a c))
;                  (else (+ a b))))
;(display (m-sum 5 5 3))
;(newline)
;
;(display "ex1.3: ")
;(define (m-sum a b c)
;            (cond ((and (< a b) (< a c)) (+ b c))
;                  ((and (< b a) (< b c)) (+ a c))
;                  (else (+ a b))))
;(display (m-sum 3 5 3))
;(newline)
;(newline)
;(display "sqrt(): ")
;(define (average x y)
;    (/ (+ x y) 2))
;
;(define (square x) (* x x))
;
;(define (good-enough? guess x)
;    (< (abs (- (square guess) x)) 0.001))
;
;(define (improve guess x)
;    (average guess (/ x guess)))
;
;(define (sqrt-iter guess x)
;    (if (good-enough? guess x)
;        guess
;        (sqrt-iter (improve guess x)
;                    x)))
;(define (sqrt x)
;    (sqrt-iter 1.0 x))
;(display (sqrt 2))
;(newline)

;(define (new-if predicate then-clause else-clause)
;    (cond (predicate then-clause)
;        (else else-clause)))
;
;(newline)
;(display "new-if: ")
;(define (p) (p))
;(display (new-if 0 0 (p)))
;(display "sqrt(): ")
;(define (sqrt-iter guess x)
;    (new-if (good-enough? guess x)
;        guess
;        (sqrt-iter (improve guess x)
;            x)))
;
;(define (sqrt x)
;    (sqrt-iter 1.0 x))
;(display (sqrt 2))
;(newline)

;(newline)
;(display "ex1.7: \n")
;(define (average x y)
;        (/ (+ x y) 2))
;
;(define (good-enough? new old)
;        (< (/ (abs (- new old)) old) 0.0000000001))
;
;(define (improve guess x)
;        (average guess (/ x guess)))
;
;(define (sqrt-iter guess x)
;        (if (good-enough? guess (improve guess x))
;            guess
;            (sqrt-iter (improve guess x) x)))
;(define (sqrt x)
;        (sqrt-iter 1.0 x))
;
;(display (sqrt 0.000001))
;(newline)

;(display "ex1.8: \n")
;
;(define (cuberoot x)
;        (cuberoot-iter 1.0 x))
;
;(display (cuberoot 0.000001))
;(newline)

;(define (gcd a b)
;        (if (= b 0)
;            a
;            (gcd b (remainder a b))))
;
;(display (gcd 206 40))
;(newline)

;(define (gcd a b remainder-count)
;  (if(= b 0)
;     (begin (display "\nremainder count: ")
;            (display remainder-count)
;            (display "\n gcd result:")
;            (display a)
;            (display "\n")
;            a)
;     (gcd b (remainder a b) (+ remainder-count 1))))
;(gcd 206 40 0)

;(define (smallest-divisor n)
;    (find-divisor n 2))
;
;(define (find-divisor n test-divisor)
;        (cond ((> (square test-divisor) n) n)
;            ((divides? test-divisor n) test-divisor)
;        (else (find-divisor n (+ test-divisor 1)))))
;
;
;(define (divides? a b)
;    (= (remainder b a) 0))
;
;(define (prime? n)
;    (= (smallest-divisor n) n))
;
;(display (prime? 101))

; (define (expmod base exp m)
;     (cond ((= exp 0) 1)
;           ((even? exp)
;               (remainder (square (expmod base (/ exp 2) m))
;                           m))
;           (else
;               (remainder (* base (expmod base (- exp 1) m))
;                           m))))

; (define (fermat-test n)
;     (define (try-it a)
;         (= (expmod a n n) a))
;     (try-it (+ 1 (random (- n 1)))))

; (define (fast-prime? n times)
;     (cond ((= times 0) true)
;         ((fermat-test n) (fast-prime? n (- times 1)))
;         (else false)))

; (define (sum-integers a b)
;   (if (> a b)
;       0
;       (+ a (sum-integers (+ a 1) b))))

; (define (sum-cubes a b)
;   (define (cube n)
;     (* n n n))
;   (if (> a b)
;       0
;       (+ (cube a) (sum-cubes (+ a 1) b))))

; (define (sum-pi a b)
;   (if (> a b)
;       0
;       (+ (/ 1.0 (* a (+ a 2))) (sum-pi (+ a 4) b))))

; (define (sum term a next b)
;   (if (> a b)
;       0
;       (+ (term a) (sum term (next a) next b))))

; (define (sum-integers a b)
;   (define (integer x) x)
;   (define (inc x) (+ x 1))
;   (sum integer a inc b))

; (define (sum-cubes a b)
;   (define (cube n) (* n n n))
;   (define (inc n) (+ n 1))
;   (sum cube a inc b))

; (define (sum-pi a b)
;   (define (pi-term x)
;     (/ 1.0 (* x (+ x 2))))
;   (define (next a) (+ a 4))
;   (sum pi-term a next b))

; (define (integral f a b dx)
;   (define (add-dx x) (+ x dx))
;   (* (sum f (+ a (/ dx 2.0)) add-dx b)
;      dx))

; (define (cube n) (* n n n))

; (define (pi-sum a b)
;     (sum (lambda (x) (/ 1.0 (* x (+ x 2))))
;          a
;          (lambda (x) (+ x 4))
;          b))

; (define (integral f a b dx)
;     (* (sum f
;             (+ a (/ dx 2.0))
;             (lambda (x) (+ x dx))
;             b)
;         dx))

;==================================== 1.3.3
; (define (search f neg pos)
;     (define (close-enough? a b)
;         (< (abs (- a b)) 0.001))
;     (define (average a b)
;         (/ (+ a b) 2))
;     (let ((mid (average neg pos)))
;         (if (close-enough? neg pos)
;             mid
;             (let ((test-value (f mid)))
;                  (cond  ((positive? test-value)
;                             (search f neg mid))
;                         ((negative? test-value)
;                             (search f mid pos))
;                         (else
;                             mid))))))

; (define (half-interval-method f a b)
;     (let    ((fa (f a))
;              (fb (f b)))
;         (cond   ((and (negative? fa) (positive? fb))
;                     (search f a b))
;                 ((and (negative? fb) (positive? fa))
;                     (search f b a))
;                 (else
;                     (error "Values are not of opposite sign" a b)))))

; (define tolerance 0.00001)

; (define (fixed-point f first-guess)
;     (define (close-enough? v1 v2)
;         (< (abs (- v1 v2)) tolerance))
;     (define (try guess)
;         (let ((next (f guess)))
;             (if (close-enough? guess next)
;                 next
;                 (try next))))
;     (try first-guess))

; (define (sqrt x)
;     (define (average a b)
;         (/ (+ a b) 2))
;     (fixed-point    (lambda (y) (average y (/ x y)))
;                     1.0))

; (display (sum-integers 1 10))
; (newline)
; (display (sum-cubes 1 10))
; (newline)
; (display (* 8 (sum-pi 1 1000)))
; (newline)
; (display (integral cube 0 1 0.0001))
; (display (* 8 (pi-sum 1 1000)))
; (newline)
; (display (integral cube 0 1 0.0001))
; (newline)
; (display (half-interval-method sin 2.0 4.0))
; (newline)
; (display (half-interval-method  (lambda (x) (- (* x x x) (* 2 x) 3))
;                                 1.0
;                                 2.0))
; (newline)
; (display (fixed-point cos 1.0))
; (newline)
; (display (fixed-point   (lambda (y) (+ (sin y) (cos y)))
;                         1.0))
; (display (sqrt 2.0))

;==================================== 1.3.4
; (define (average-damp f)
;     (define (average a b)
;         (/ (+ a b) 2))
;     (lambda (x) (average x (f x))))

; (define tolerance 0.00001)
; (define (fixed-point f first-guess)
;     (define (close-enough? a b)
;         (< (abs (- a b)) tolerance))
;     (define (try guess)
;         (let ((next (f guess)))
;             (if (close-enough? next guess)
;                 next
;                 (try next))))
;     (try first-guess))

; (define (sqrt x)
;     (fixed-point (average-damp (lambda (y) (/ x y)))
;                 1.0))

; (define (cube-root x)
;     (fixed-point (average-damp (lambda (y) (/ x (* y y))))
;                 1.0))

; (display ((average-damp square) 10))
; (newline)
; (display (fixed-point cos 1.0))
; (newline)
; (display (sqrt 2))
; (newline)
; (display (cube-root 4.0))

(define dx 0.00001)
(define (derivative g)
    (lambda (x)
        (/  (- (g (+ x dx)) (g x))
            dx)))

; (define (cube x) (* x x x))
; (display ((derivative cube) 1))

(define (newton-transform g)
    (lambda (x)
        (- x (/ (g x) ((derivative g) x)))))

(define (newtons-method g guess)
    (define tolerance 0.00001)
    (define (fixed-point f first-guess)
        (define (good-enough? a b)
            (< (abs (- a b)) tolerance))
        (define (try guess)
            (let ((next (f guess)))
                (if (good-enough? next guess)
                    next
                    (try next))))
        (try first-guess))
    (fixed-point (newton-transform g) guess))

(define (sqrt x)
    (newtons-method (lambda (y) (- (square y) x)) 1.0))

(display (sqrt 2))
(newline)

(define (fixed-point-of-transform g transform guess)
    (define tolerance 0.00001)
    (define (fixed-point f first-guess)
        (define (good-enough? a b)
            (< (abs (- a b)) tolerance))
        (define (try guess)
            (let ((next (f guess)))
                (if (good-enough? next guess)
                    next
                    (try next))))
        (try first-guess))
    (fixed-point (transform g) guess))

(define (sqrt x)
    (fixed-point-of-transform (lambda (y) (- (square y) x))
                                newton-transform
                                1.0))
(display (sqrt 2))
(newline)

(define (sqrt x)
    (define (average-damp f)
        (lambda (y) (/ (+ y (f y)) x)))
    (fixed-point-of-transform (lambda (y) (/ x y))
                                average-damp
                                1.0))
(display (sqrt 2))

(display "\n========================================\n")
